import org.geotools.data.*;
import org.geotools.data.shapefile.ShapefileDataStoreFactory;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geometry.jts.JTS;
import org.geotools.map.FeatureLayer;
import org.geotools.map.MapContent;
import org.geotools.referencing.CRS;
import org.geotools.styling.SLD;
import org.geotools.styling.Style;
import org.geotools.swing.JMapFrame;
import org.geotools.swing.data.JFileDataStoreChooser;
import org.locationtech.jts.geom.Geometry;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

public class GeometryCRS {
    public static void main(String[] args) throws Exception {
        // 选择shp文件
        File sourceFile = JFileDataStoreChooser.showOpenFile("shp", null);

        // 获取FeatureSource
        FileDataStore dataStore = FileDataStoreFinder.getDataStore(sourceFile);
        SimpleFeatureSource featureSource = dataStore.getFeatureSource();

        // 构造地图和图层
        MapContent map = new MapContent();
        Style style = SLD.createSimpleStyle(featureSource.getSchema());
        FeatureLayer featureLayer = new FeatureLayer(featureSource, style);
        map.addLayer(featureLayer);

        // 地图展示
        JMapFrame frame = new JMapFrame(map);
        frame.enableToolBar(true);
        frame.enableStatusBar(true);
        frame.setTitle("地图展示");
        frame.setLocation(200, 0);

        // 添加按钮事件
        JToolBar toolBar = frame.getToolBar();
        toolBar.removeAll();
        JButton btnExport = new JButton("导出重投影shp");
        btnExport.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 配置保存对话框
                JFileDataStoreChooser chooser = new JFileDataStoreChooser("shp");
                chooser.setDialogTitle("save reprojected shapefile1");
                chooser.setSaveFile(sourceFile);

                // 对话框操作判断
                int returnVal = chooser.showSaveDialog(null);
                if (returnVal != JFileDataStoreChooser.APPROVE_OPTION) return;
                File file = chooser.getSelectedFile();
                if (file.equals(sourceFile)) {
                    JOptionPane.showMessageDialog(null, "Can't replace " + file);
                    return;
                }

                SimpleFeatureType schema = featureSource.getSchema();
                CoordinateReferenceSystem dataCRS = schema.getCoordinateReferenceSystem();
                CoordinateReferenceSystem wordCRS = map.getCoordinateReferenceSystem();
                try {
                    // 初始化DataStore仓库
                    MathTransform transform = CRS.findMathTransform(dataCRS, wordCRS, true);
                    SimpleFeatureCollection featureCollection = featureSource.getFeatures();
                    ShapefileDataStoreFactory storeFactorySpi = new ShapefileDataStoreFactory();

                    // 生成DataStore
                    Map<String, Serializable> create = new HashMap<>();
                    create.put("url", file.toURI().toURL());
                    create.put("create spatial index", Boolean.TRUE);
                    DataStore dataStore = storeFactorySpi.createNewDataStore(create);
                    SimpleFeatureType featureType = SimpleFeatureTypeBuilder.retype(schema, wordCRS);
                    dataStore.createSchema(featureType);

                    // 生成FeatureWriter
                    String createdName = dataStore.getTypeNames()[0];
                    Transaction transaction = new DefaultTransaction("reprojected");
                    FeatureWriter<SimpleFeatureType, SimpleFeature> writer =
                            dataStore.getFeatureWriterAppend(createdName, transaction);

                    // 遍历features, 依次更改geometry
                    SimpleFeatureIterator iterator = featureCollection.features();
                    while (iterator.hasNext()) {
                        SimpleFeature feature = iterator.next();
                        SimpleFeature copy = writer.next();
                        copy.setAttributes(feature.getAttributes());

                        Geometry geometry = (Geometry) feature.getDefaultGeometry();
                        Geometry geometry2 = JTS.transform(geometry, transform);

                        copy.setDefaultGeometry(geometry2);
                        writer.write();
                    }
                    transaction.commit();
                    JOptionPane.showMessageDialog(null, "Export to shapefile complete");

                } catch (FactoryException | IOException factoryException) {
                    factoryException.printStackTrace();
                } catch (TransformException transformException) {
                    transformException.printStackTrace();
                }
            }
        });
        toolBar.add(btnExport);

        frame.setSize(1400, 1000);
        frame.setVisible(true);
    }
}
